home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Modules / BackSpaceModules / Source / MartinView / MartinView.m < prev    next >
Text File  |  1992-11-03  |  15KB  |  588 lines

  1. #import "MartinView.h"
  2. #import "Thinker.h"
  3. #import <math.h>
  4. #import <libc.h>
  5. #import <streams/streams.h>
  6. #import <defaults/defaults.h>
  7. #import <appkit/color.h>
  8. #import <appkit/graphics.h>
  9. #import <dpsclient/wraps.h>
  10. #import <appkit/Button.h>
  11. #import <appkit/Application.h>
  12.  
  13. /* MartinView:  a BackSpace.app v3.0 module             by Jeffrey Adams
  14.  * version 1.0                                             jeffa@wri.com
  15.  */
  16.  
  17. char fname[Nfunc][16] = { "martin1", "martin2", "ejk1", "ejk2" };
  18.  
  19. /* The file used to store remembered fractals */
  20. char    fileName[] = "/.martinView";
  21.  
  22. @implementation MartinView
  23.  
  24. /* Implemented so you can screen grab the image if you want to (at least I wanted to!) */
  25. - pause:sender
  26. {
  27.     isPaused = [sender state];
  28.     return self;
  29. }
  30.  
  31. /* Inherited method for setting the graphics state before sending OneSteps */
  32. - didLockFocus
  33. {
  34.     NXSetColor(currColor);
  35.     return self;
  36. }
  37.  
  38. - oneStep
  39. {
  40.     NXRect *currentPixel = pixels;
  41.  
  42.     if (isPaused) return self;
  43.  
  44.     /* Stay in here until we hit our flush buffer limit or we hit the maximum
  45.        total points allowed */
  46.     while ((++nd < nD) && (++nP < mxP)) {
  47.     
  48.     switch (Function) {
  49.         case Ejk1: x1 = y  - ( (x>0) ? (B*x-C) : -(B*x-C) ); break;
  50.         case Martin1:  x1 = y  - ( (x<0) ? sqrt(fabs(B*x-C)) : -sqrt(fabs(B*x-C)) ); break;
  51.         case Ejk2: x1 = y  - ( (x<0) ? log(fabs(B*x-C)) : -log(fabs(B*x-C)) ); break;  
  52.         case Martin2:  x1 = y  - sin(x); break;
  53.         }
  54.     y = A - x; x=x1;
  55.      
  56.     /* seed perturbation */
  57.      if (Pn && ++pn > Pn) {
  58.          x += (x>0) ? -Pv : Pv;
  59.          y += (y>0) ? -Pv : Pv;
  60.          pn = 0;
  61.          }
  62.  
  63.      /* Do we need to change the color?  */
  64.      if (++nc > nC) {
  65.         color = (color+1)%Ncolors;
  66.         /* Since we are changing color, send buffered points to screen */
  67.         if (numPixels) {
  68.             NXRectFillList(pixels, numPixels);
  69.             numPixels = 0; currentPixel = pixels;
  70.             }
  71.         currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) : 
  72.                 NXConvertGrayToColor(Ranf())) : colors[color];
  73.         NXSetColor(currColor);
  74.          nc = 0;
  75.         }
  76.      
  77.     /*  If we are not within the screen range, do not store them  */
  78.     iy = cy + Zf*y; if (iy < 0 || iy > mxY) continue;
  79.     ix = cx + Zf*x; if (ix < 0 || ix > mxX) continue;
  80.  
  81.     /* Update the data needed for the NXRectFillList */
  82.     currentPixel->origin.x = ix;  currentPixel->origin.y = iy;
  83.     ++numPixels; ++currentPixel;
  84.  
  85.     /* Have we hit the in-range limit, if so, send the buffer to the screen */
  86.     if (++np > mxp) {
  87.           if (numPixels) {
  88.             NXRectFillList(pixels, numPixels);
  89.             numPixels = 0; currentPixel = pixels;
  90.             }
  91.           [self newOne:self];
  92.         break;
  93.         }
  94.     }
  95.     nd = 0;
  96.     /* Flush buffer full, display pixels */
  97.     if (numPixels) {
  98.         NXRectFillList(pixels, numPixels);
  99.         numPixels = 0; currentPixel = pixels;
  100.         }
  101.     /* If we left because we hit max total limit, give us a new one */
  102.     if(nP == mxP) 
  103.           [self newOne:self];
  104.     return self;
  105. }
  106.  
  107. - newOne:sender   
  108. {
  109.     double  A1, B1, C1;        /* 2nd part of parameter range             */
  110.     char    name[15],str[20];
  111.     NXStream    *stream;
  112.     int    i;
  113.         
  114.     [self display]; 
  115.     if (!smallInspect) return nil;
  116.  
  117.     /* Record current settings in Defaults database */
  118.     sprintf(str,"%d", ([funcAuto state]) ? -1 : Function);
  119.     NXWriteDefault([NXApp appName], "MartinFunction", str);
  120.     sprintf(str,"%d", ([maxTotFlag state]) ? -1 : [maxTotalPts intValue]);
  121.     NXWriteDefault([NXApp appName], "MartinMaxTot", str);
  122.     sprintf(str,"%d", ([maxInFlag state]) ? -1 : [maxInRangePts intValue]);
  123.     NXWriteDefault([NXApp appName], "MartinMaxIn", str);
  124.     sprintf(str,"%d", ([colFlag state]) ? -1 : [colInterval intValue]);
  125.     NXWriteDefault([NXApp appName], "MartinColorInt", str);
  126.     
  127.     np = 0; nP = 0; nd = 0; numPixels=0;
  128.     x = y = 0; color = -1;
  129.     Ranfset(time(0));
  130.     W = (int)bounds.size.width;
  131.     H = (int)bounds.size.height; 
  132.     mxX = W-1; mxY = H-1;
  133.  
  134.     /* If we are using a file, load the settings from '.martinView'  */
  135.     if (streamPos >= 0) {
  136.         if (!(stream = NXMapFile(file, NX_READONLY))) {
  137.             streamPos = -1;
  138.             [useFileFlag setState:NO];
  139.             [self newOne:self];
  140.             return self;
  141.             }
  142.         for (i=0; i <= streamPos; ++i) {
  143.             if(NXAtEOS(stream)){
  144.                 streamPos = 0; i=-1;
  145.                 NXSeek(stream, 0, NX_FROMSTART);
  146.                 if(NXAtEOS(stream)) {
  147.                     streamPos =-1;
  148.                     [useFileFlag setState:NO];
  149.                     [self newOne:self];
  150.                     return self;
  151.                     }
  152.                 continue;
  153.                 }
  154.             NXScanf(stream, "%s\n",name);
  155.             NXScanf(stream, "%d %le\n",&Pn,&Pv);
  156.             NXScanf(stream, "%d\n",&Function);
  157.             NXScanf(stream, "%le %le %le %le\n",&A,&B,&C,&Zf);
  158.             NXScanf(stream, "%d %d %d\n",&mxp,&mxP,&nC);
  159.             NXScanf(stream, "%d %d\n",&moveX,&moveY);
  160.             }
  161.         streamPos++;
  162.         NXCloseMemory(stream, NX_FREEBUFFER);
  163.         }
  164.     else {
  165.     
  166.     if ([seedIntFlag state]) Pn = pow(10., 1+Ranf()*3);
  167.     else Pn = [seedPertInt intValue];
  168.     if ([seedValFlag state]) Pv = pow(10.,Ranf()*3);
  169.     else Pv = [seedPertVal doubleValue];
  170.  
  171.    /* provide default hopalong parameters if needed */ 
  172.    if ([funcAuto state]) {
  173.       double r = Ranf();
  174.       if      (r < 0.40) Function = Martin1;
  175.       else if (r < 0.70) Function = Ejk1;
  176.       else if (r < 0.90) Function = Ejk2;
  177.       else               Function = Martin2;
  178.       }
  179.     if (Function == Martin1) {
  180.       if ([aFlag state]) A = 40 + Ranf()*1500;
  181.       if ([bFlag state]) B = 3  + Ranf()*17;
  182.       if ([cFlag state]) C = 100 + Ranf()*3000;
  183.       }
  184.    else if (Function == Martin2) {
  185.       if ([aFlag state]) A = 3.075927 + Ranf()*0.14;
  186.       }
  187.    else if (Function == Ejk1) {
  188.       if ([aFlag state]) A = Ranf()*500;
  189.       if ([bFlag state]) B = Ranf()*.40;
  190.       if ([cFlag state]) C = 10 + Ranf()*100;
  191.       }
  192.    else if (Function == Ejk2) {
  193.       if ([aFlag state]) A = Ranf()*500; 
  194.       if ([bFlag state]) B = pow(10.,6+Ranf()*24);
  195.       if ([cFlag state]) C = pow(10.,  Ranf()*9);
  196.       }
  197.     if(![aFlag state]) A = [hopAField doubleValue];
  198.     if(![bFlag state]) B = [hopBField doubleValue];
  199.     if(![cFlag state]) C = [hopCField doubleValue];
  200.   
  201.    if (A1 = [a1Flag state]) A = Min(A,A1) + Ranf()*(Max(A,A1) - Min(A,A1));
  202.    if ([afFlag state] && Ranf()<0.5) A = -A;
  203.    if (B1 = [b1Flag state]) B = Min(B,B1) + Ranf()*(Max(B,B1) - Min(B,B1));
  204.    if ([bfFlag state] && Ranf()<0.5) B = -B;
  205.    if (C1 = [c1Flag state]) C = Min(C,C1) + Ranf()*(Max(C,C1) - Min(C,C1));
  206.    if ([cfFlag state] && Ranf()<0.5) C = -C;
  207.    
  208.    if ([magFlag state]) Zf = (Function == Martin2) ? 4.0 : 1.0;
  209.    else Zf = [magField doubleValue];
  210.     
  211.     if ([maxInFlag state]) mxp = (int) (0.40* (float)(W*H));
  212.     else mxp = [maxInRangePts intValue];
  213.     if ([maxTotFlag state]) mxP = 4 * mxp;
  214.     else mxP = [maxTotalPts intValue];
  215.     
  216.     /* color processing */
  217.     if ([colFlag state]) nC = (mxP/Ncolors)/2;
  218.     else nC = [colInterval intValue];
  219.     }
  220.     nc = nC;
  221.     cx = W/2+moveX; cy = H/2+moveY;
  222.     [displaceX setIntValue:moveX];
  223.     [displaceY setIntValue:moveY];
  224.     [seedPertInt setIntValue:Pn];
  225.     [seedPertVal setDoubleValue:Pv];
  226.     [dynamFlush setIntValue:nD];
  227.     [funcButton setTitle:fname[Function]];
  228.     [hopAField setDoubleValue:A];
  229.        [hopBField setDoubleValue:B];
  230.        [hopCField setDoubleValue:C];
  231.        [magField setDoubleValue:Zf];
  232.     [maxInRangePts setIntValue:mxp];
  233.     [maxTotalPts setIntValue:mxP];
  234.     [colInterval setIntValue:nC];
  235.     return self;
  236. }
  237.    
  238. - changeFunc:sender
  239. {
  240.     char    str[10];
  241.     
  242.     Function = [sender selectedTag];
  243.     [funcAuto setState:NO];
  244.     sprintf(str,"%d", Function);
  245.     NXWriteDefault([NXApp appName], "MartinFunction", str);
  246.     [self newOne:sender];
  247.     return self;
  248. }
  249. - changeDynam:sender
  250. {    
  251.     nD = [sender intValue];
  252.     if ((nD <1) || (nD > MAXDYNAMPOINTS))
  253.         nD = MAXDYNAMPOINTS;
  254.     [dynamFlush setIntValue:nD];
  255.     [self makeNewDynam:nD];
  256.     [self newOne:sender];
  257.     return self;
  258. }
  259.  
  260. /* We create the array of NXRects ahead of time so we do not waste time
  261.    building the array up as we go along */
  262. - makeNewDynam:(int)num
  263. {
  264.     NXRect *curr;
  265.     NXSize pixSize = {1,1};
  266.  
  267.     if (pixels)
  268.        free(pixels);
  269.     pixels = (NXRect *)malloc(sizeof(NXRect)*(num+1));
  270.     for (curr = pixels; curr-pixels < num; ++curr)
  271.         curr->size = pixSize;
  272.     return self;
  273. }
  274. - setHopA:sender
  275. {
  276.     if ([sender doubleValue] > 0) [aFlag setState:NO];
  277.     [self newOne:sender];
  278.     return self;
  279. }
  280. - setHopB:sender
  281. {
  282.     if ([sender doubleValue] > 0) [bFlag setState:NO];
  283.     [self newOne:sender];
  284.     return self;
  285. }
  286. - setHopC:sender
  287. {
  288.     if ([sender doubleValue] > 0) [cFlag setState:NO];
  289.     [self newOne:sender];
  290.     return self;
  291. }
  292.  
  293. - setSeedInt:sender
  294. {
  295.     if ([sender intValue] > 0) [seedIntFlag setState:NO];
  296.     [self newOne:sender];
  297.     return self;
  298. }
  299. - setMagnification:sender
  300. {
  301.     if ([sender doubleValue] >= 0) [magFlag setState:NO];
  302.     [self newOne:sender];
  303.     return self;
  304. }
  305.  
  306. - setSeedVal:sender
  307. {
  308.     if ([sender doubleValue] >= 0) [seedValFlag setState:NO];
  309.     [self newOne:sender];
  310.     return self;
  311. }
  312. - setDisplacement:sender
  313. {
  314.     moveX = [displaceX intValue];
  315.     moveY = [displaceY intValue];
  316.     [self newOne:sender];
  317.     return self;
  318. }
  319.  
  320. - setColChange:sender
  321. {
  322.     char str[30];
  323.     
  324.     if ([sender intValue] > 0) {
  325.         [colFlag setState:NO];
  326.         sprintf(str,"%d", [sender intValue]);
  327.         NXWriteDefault([NXApp appName], "MartinColorInt", str);
  328.         }
  329.     [self newOne:sender];
  330.     return self;
  331. }
  332.  
  333. - setMaxTot:sender
  334. {
  335.     char str[30];
  336.     
  337.     if ([sender intValue] > 0) {
  338.         [maxTotFlag setState:NO];
  339.         sprintf(str,"%d", [sender intValue]);
  340.         NXWriteDefault([NXApp appName], "MartinMaxTot", str);
  341.         }
  342.     [self newOne:sender];
  343.     return self;
  344. }
  345. - setMaxIn:sender
  346. {
  347.     char str[30];
  348.     
  349.     if ([sender intValue] > 0) {
  350.         [maxInFlag setState:NO];
  351.         sprintf(str,"%d", [sender intValue]);
  352.         NXWriteDefault([NXApp appName], "MartinMaxIn", str);
  353.         }
  354.     [self newOne:sender];
  355.     return self;
  356. }
  357. - setRandomColor:sender
  358. {
  359.     char str[10];
  360.     
  361.     Randomcolor = [sender state];
  362.     sprintf(str,"%d", Randomcolor);
  363.     NXWriteDefault([NXApp appName], "MartinRandomCol", str);
  364.     [self newOne:sender];
  365.     return self;
  366. }
  367. - changeColorMode:sender
  368. {
  369.     int    newColMode;
  370.     char    str[10];
  371.     
  372.     newColMode = [sender selectedTag];
  373.     if (Color != newColMode) {
  374.         Color = newColMode;
  375.         [self convertColors];
  376.         sprintf(str,"%d",Color);
  377.         NXWriteDefault([NXApp appName], "MartinColorMode", str);
  378.         }
  379.     [self newOne:self];
  380.     return self;
  381. }
  382.  
  383. /* Weak way of changing from nonrandom color array to nonrandom gray array */
  384. - convertColors
  385. {
  386.     if (Color){
  387.         Ncolors = DEFAULTNUMCOLORS;
  388.         colors[0] = NX_COLORBLUE;  
  389.         colors[1] = NX_COLORBROWN;
  390.         colors[2] = NX_COLORWHITE; 
  391.         }
  392.     else{
  393.         Ncolors = 3;
  394.         colors[0] = NX_COLORWHITE;  
  395.         colors[1] = NX_COLORDKGRAY;
  396.         colors[2] = NX_COLORLTGRAY;
  397.         }
  398.     return self;
  399. }
  400.  
  401. /* Append the current fractal info (all of it) in the data file */
  402. - remember:sender
  403. {
  404.     NXStream    *stream;
  405.     
  406.     if (!(stream = NXMapFile(file, NX_WRITEONLY))) {
  407.         stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  408.         }
  409.     NXSeek(stream, 0, NX_FROMEND);
  410.     NXPrintf(stream, "MartinView\n");
  411.     NXPrintf(stream, "%d %.15le\n",Pn,Pv);
  412.     NXPrintf(stream, "%d\n",Function);
  413.     NXPrintf(stream, "%.15le %.15le %.15le %.15le\n",A,B,C,Zf);
  414.     NXPrintf(stream, "%d %d %d\n",mxp,mxP,nC);
  415.     NXPrintf(stream, "%d %d\n",moveX,moveY);
  416.     NXSaveToFile(stream, file);
  417.     NXCloseMemory(stream, NX_FREEBUFFER);
  418.     return self;
  419. }
  420.  
  421. - useFile:sender
  422. {
  423.     NXStream    *stream;
  424.     char    name[15],str[10];
  425.     
  426.     if ([sender state]) {
  427.         if (!(stream = NXMapFile(file, NX_READONLY))) {
  428.             [sender setState:NO];
  429.             streamPos = -1;
  430.             [self newOne:self];
  431.             }
  432.         else {
  433.             NXScanf(stream, "%s\n",name);
  434.             if (strcmp("MartinView",name)) {
  435.                 [sender setState:NO];
  436.                 streamPos = -1;
  437.                 }
  438.             else  streamPos = 0;
  439.             NXCloseMemory(stream, NX_FREEBUFFER);
  440.             [self newOne:self];
  441.             }
  442.         }
  443.     else {
  444.         streamPos = -1;
  445.         [self newOne:self];
  446.         }
  447.     sprintf(str,"%d",[sender state]);
  448.     NXWriteDefault([NXApp appName], "MartinUseFile", str);
  449.     return self;
  450. }
  451.  
  452. - initFrame:(NXRect *)frameRect
  453. {    
  454.     [super initFrame:frameRect];
  455.  
  456.     [self allocateGState];        // For faster lock/unlockFocus
  457.     strcpy(file,NXHomeDirectory());
  458.     strcat(file,fileName);
  459.     srandom(getpid());
  460.     isPaused = 0;
  461.     Ncolors = DEFAULTNUMCOLORS;
  462.     colors = (NXColor *)malloc(sizeof(NXColor)*Ncolors);
  463.     colors[0] = NX_COLORBLUE;  
  464.     colors[1] = NX_COLORBROWN;
  465.     colors[2] = NX_COLORWHITE; 
  466.     colors[3] = NX_COLORCYAN;
  467.     colors[4] = NXConvertRGBToColor(250,128, 114);
  468.     colors[5] = NX_COLORGRAY;
  469.     colors[6] = NX_COLORGREEN; 
  470.     colors[7] = NXConvertRGBToColor(255,87, 33);
  471.     colors[8] = NX_COLORMAGENTA; 
  472.     colors[9] = NX_COLORORANGE;
  473.     colors[10] = NX_COLORPURPLE; 
  474.     colors[11] = NX_COLORRED;
  475.     colors[12] = NXConvertRGBToColor(227,207, 87); 
  476.     colors[13] = NX_COLORYELLOW;
  477.     moveX = 0; moveY = 0;
  478.     Ranfseed=4326;
  479.     nD = STARTDYNAMPOINTS;
  480.     [self makeNewDynam:nD];    
  481.     return self;
  482. }
  483.  
  484. - inspectorWillBeRemoved
  485. {
  486.     [myPrefPanel  orderOut:self];
  487.     return self;
  488. }
  489.  
  490. - inspector:sender
  491. {
  492.     char buf[MAXPATHLEN];
  493.     int value;
  494.  
  495.     if (!smallInspect)
  496.     {
  497.         sprintf(buf,"%s/MartinPrefs.nib",[sender moduleDirectory:"Martin"]);
  498.         [NXApp loadNibFile:buf owner:self withNames:NO];
  499.         Function=atoi(NXGetDefaultValue([NXApp appName], "MartinFunction"));
  500.         if (Function == -1) 
  501.             [funcAuto setState:YES];
  502.         else {
  503.             [funcAuto setState:NO];
  504.             [funcButton setTitle:fname[Function]];
  505.             }
  506.         if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxTot"))) == -1)
  507.             [maxTotFlag setState:YES];
  508.         else {
  509.             [maxTotFlag setState:NO];
  510.             [maxTotalPts setIntValue:value];
  511.             }
  512.         if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxIn"))) == -1)
  513.             [maxInFlag setState:YES];
  514.         else {
  515.             [maxInFlag setState:NO];
  516.             [maxInRangePts setIntValue:value];
  517.             }
  518.         if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinColorInt"))) == -1)
  519.             [colFlag setState:YES];
  520.         else {
  521.             [colFlag setState:NO];
  522.             [colInterval setDoubleValue:value];
  523.             }
  524.         Randomcolor = atoi(NXGetDefaultValue([NXApp appName], "MartinRandomCol"));
  525.         [randomFlag setState:Randomcolor];
  526.         Color=atoi(NXGetDefaultValue([NXApp appName], "MartinColorMode"));                      
  527.         if (Color) [colorButton setTitle:"Color"];
  528.             else [colorButton setTitle:"Mono"];
  529.         [self convertColors];
  530.         currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) : 
  531.                 NXConvertGrayToColor(Ranf())) : colors[0];
  532.         [useFileFlag setState:atoi(NXGetDefaultValue([NXApp appName], "MartinUseFile"))];
  533.         if ([useFileFlag state]) 
  534.             [self useFile:useFileFlag];
  535.         else {
  536.             streamPos =-1;
  537.             [self newOne:self];
  538.             }
  539.     }
  540.     return smallInspect;
  541. }
  542.  
  543. + initialize
  544. {
  545.     static NXDefaultsVector MartinViewDefaults = {{"MartinFunction", "-1"},
  546.         {"MartinMaxTot", "-1"},{"MartinMaxIn", "-1"},
  547.         {"MartinColorInt", "-1"},{"MartinRandomCol", "1"},{"MartinColorMode", "1"},
  548.         {"MartinUseFile", "0"},{NULL,NULL} };
  549.     NXRegisterDefaults([NXApp appName], MartinViewDefaults);
  550.     return self;
  551. }
  552.  
  553. - sizeTo:(NXCoord)width :(NXCoord)height
  554. {
  555.     [super sizeTo:width :height];
  556.     [self newOne:self];
  557.     return self;
  558. }
  559.  
  560. - drawSelf:(const NXRect *)rects :(int)rectCount
  561. {
  562.     if (!rects || !rectCount) return self;
  563.     PSsetgray(0.0);
  564.     NXRectFill(rects); // black screen
  565.     return self;
  566. }
  567.  
  568. - free
  569. {
  570.     if (pixels)
  571.         free(pixels);
  572.     if (Ncolors)
  573.         free(colors);
  574.        return [super free];
  575. }
  576.  
  577. /* Why not a little fluff */
  578. - windowWillMiniaturize:sender toMiniwindow:miniwindow
  579. {
  580.      [sender setMiniwindowIcon:"MartinMini"];
  581.     return self;    
  582. }
  583.  
  584. - (BOOL) useBufferedWindow {  return NO; }
  585. - (const char *) windowTitle { return ( const char * ) "Martin Fractals";}
  586.  
  587. @end
  588.